#include "StompedReality/Asset/AssetManager.h"
#include "StompedReality/Asset/PatchSystem.h"
#include "StompedReality/Asset/TextureInfo.h"
#include "StompedReality/Core/FileSystem.h"
#include "StompedReality/Core/Graphics/GLExtensions.h"
#include "StompedReality/Core/IGame.h"
#include "StompedReality/Core/Logger.h"
StompedReality::Asset::PatchSystem::PatchSystem( ) : StompedReality::GameAccess( )
{
  this->m_PatchList = 0;
  this->m_Capacity = 0;
}

StompedReality::Asset::PatchSystem::~PatchSystem( )
{
  LogCallFunctionInfo( "PatchSystem", "Destructor" );
  if ( StompedReality::Graphics::GLExtensions::glInitialized )
  {
    for ( int i = 0; i < this->m_Capacity; ++i )
    {
      if ( this->HasPatchInfo ( i ) )
      {
        StompedReality::ID id = this->GetGLPatchBindingID ( i );
        StompedReality::Graphics::GLExtensions::glDeleteBuffersARB ( 1, &id );
      }
    }
  }
  delete[] this->m_PatchList;
}

void StompedReality::Asset::PatchSystem::Initialize ( int capacity )
{
  if ( this->m_Capacity != 0 )
  {
    LogCallFunctionWarning( "PatchSystem", "Initialize", "re-initialization" );
    return;
  }
  this->m_PatchList = new StompedReality::Asset::PatchInfo[capacity];
  this->m_Capacity = capacity;
  LogCallFunctionInfo( "PatchSystem", "Initialize" );
  LogInfoPair( "capacity", capacity );
}

const StompedReality::Asset::PatchInfo StompedReality::Asset::PatchSystem::GetPatchInfo ( const ID id )
{
  return this->m_PatchList[id];
}

const StompedReality::ID StompedReality::Asset::PatchSystem::GetGLPatchBindingID ( const StompedReality::ID id )
{
  return this->m_PatchList[id].glBinding;
}

bool StompedReality::Asset::PatchSystem::HasPatchInfo ( StompedReality::ID id )
{
  return this->m_PatchList[id].glBinding != 0xffffffff;
}

void StompedReality::Asset::PatchSystem::ReadFromFile ( const char* fileName )
{
  if ( !StompedReality::Graphics::GLExtensions::glInitialized )
  {
    LogCallFunctionError( "PatchSystem", "ReadFromFile", "GLExtensions not initialized" );
    return;
  }
  LogCallFunctionInfo( "PatchSystem", "ReadFromFile" );
  LogInfoPair( "fileName", fileName );
  Json::Value root = *(this->m_Game->getFileSystem( )->openAsJson( fileName ));
  for ( unsigned i = 0; i < root["Patches"].size( ); ++i )
  {
    this->ParsePatch ( root["Patches"][i] );
  }
}

void StompedReality::Asset::PatchSystem::ParsePatch ( Json::Value& root )
{
  // get values
  StompedReality::ID id = root["id"].asUInt( );
  StompedReality::ID textureID = root["texture"].asUInt( );
  int x = root["position"]["x"].asInt( );
  int y = root["position"]["y"].asInt( );
  int w = root["size"]["x"].asInt( );
  int h = root["size"]["y"].asInt( );

  LogCallFunctionInfo( "PatchSystem", "ParsePatch" );
  LogInfoPair( "id", id );
  LogInfoPair( "textureID", textureID );

// texture exists ?
  if ( !this->m_Game->getAssetManager( )->HasTextureInfo ( textureID ) )
  {
    LogCallFunctionWarning( "PatchSystem", "ParsePatch", "texture not found" );
    return;
  }

  // get texture binding
  StompedReality::Asset::TextureInfo textureInfo = this->m_Game->getAssetManager( )->
    GetTextureInfo ( textureID );

  // create data
  float* data = this->CalculateBufferRect ( w, h );
  this->UpdateUV ( data, textureInfo.width, textureInfo.height, x, y, w, h );

  // get patch
  PatchInfo patch = this->GetPatchInfo ( id );
  patch.textureID = textureInfo.glBinding;

  // copy data
  StompedReality::Graphics::GLExtensions::glGenBuffersARB ( 1, &( patch.glBinding ) );
  StompedReality::Graphics::GLExtensions::glBindBufferARB ( GL_ARRAY_BUFFER, patch.glBinding );
  StompedReality::Graphics::GLExtensions::glBufferDataARB ( GL_ARRAY_BUFFER, sizeof ( GLfloat ) * 16, data,
                                                            GL_STATIC_DRAW );
  delete[] data;

  // store patch
  this->m_PatchList[id] = patch;
}

bool StompedReality::Asset::PatchSystem::ParseConfig ( Json::Value& root )
{
  LogCallFunctionInfo( "PatchSystem", "ParseConfig" )

  this->Initialize ( root["PatchSystem"].get ( "capacity", 512 ).asInt( ) );
  return true;
}

